package com.ezops.poc.validations.validators;

import java.lang.reflect.Field;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.ezops.poc.validations.result.FieldValidationError;
import com.ezops.poc.validations.result.ValidationResult;

/**
 * Checks if the field being passed lies in the specified range.
 * 
 * @author vgaurav
 * 
 */
@Component
@Validator(name = "Range")
public class RangeValidator extends AbstractValidator {

	private static final Logger logger = LoggerFactory
			.getLogger(RangeValidator.class);

	private String minValue, maxValue;
	private RangeType type = RangeType.NONE;

	enum RangeType {
		LESS_THAN, GREATER_THAN, BETWEEN, NONE;
	}

	public RangeValidator() {
	}

	@Override
	public void init(String fieldName, String... param) {
		logger.debug(
				"Initializing range validator instance, parameter passed is {}",
				param.toString());
		if (param == null || param.length == 0) {
			return;
		}
		this.ezopsDisplayFieldName = fieldName;

		String[] values = param[0].trim().split("");

		// value[0] would be ""
		if (">".equals(values[1])) {
			this.type = RangeType.GREATER_THAN;
			this.minValue = values[2];
		} else if ("<".equals(values[1])) {
			this.type = RangeType.LESS_THAN;
			this.maxValue = values[2];
		} else {
			if (param[0].contains("-")) {
				this.type = RangeType.BETWEEN;
				values = param[0].split("-");
				this.minValue = values[0];
				this.maxValue = values[1];
			} else {

				throw new IllegalArgumentException(
						"Range validation shoud either be > or < or between like x-y");
			}
		}
	}

	@Override
	public ValidationResult validateModel(Object model) {
		if (model == null) {
			throw new IllegalArgumentException("Can't not validate null model");
		}
		if (this.type.equals(RangeType.NONE)) {
			return ValidationResult.getValidResponse();
		}
		final Integer value;

		try {
			final Field field = model.getClass().getDeclaredField(fieldName);
			field.setAccessible(true);

			String fieldValue = (String) field.get(model);
			// If the value itself is not present (either null or empty), should
			// return true, since there is no point doing the range validation.
			// We are not doing mandatory check here. If this field is non
			// mandatory , then it can be null or empty
			if (fieldValue == null || fieldValue.trim().equals("")) {
				return ValidationResult.getValidResponse();
			}

			value = Integer.parseInt((String) field.get(model));
			switch (type) {
			case LESS_THAN:
				if (value < Integer.parseInt(maxValue)) {
					return ValidationResult.getValidResponse();
				}
				break;
			case GREATER_THAN:
				if (value.intValue() > Integer.parseInt(minValue)) {
					return ValidationResult.getValidResponse();
				}
				break;
			case BETWEEN:
				if (value.intValue() > Integer.parseInt(minValue)
						&& value < Integer.parseInt(maxValue)) {
					return ValidationResult.getValidResponse();

				}
				break;
			case NONE:
				throw new IllegalArgumentException("Un reachable code");
			}

		} catch (Exception ex) {
			logger.error("Error while performing range validation, reason -",
					ex.getMessage());
		}
		return ValidationResult.getErrorResponse(new FieldValidationError() {

			public String getFieldName() {
				return fieldName;
			}

			public String getErrorMessage() {
				return "The field name " + fieldName
						+ " is not in correct range.";
			}
		});
	}

}
